{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.异常\n",
    "\n",
    "### 1.1 try...except\n",
    "\n",
    "又到了开新课的时候了，小明同学这次提前预习了知识，乘着老师还没来就在黑板上写下了这段Code："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "division by zero\n"
     ]
    }
   ],
   "source": [
    "def main():\n",
    "    try:\n",
    "        1 / 0  # ZeroDivisionError: division by zero\n",
    "    except ZeroDivisionError as ex:\n",
    "        print(ex)\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 try...except...else...finally\n",
    "\n",
    "小潘同学刚进来就看见了，自语道：“`try...except`捕获异常谁不会？就会这么屁点东西还好意思秀，切～ 我给你把 **格式**补全”\n",
    "\n",
    "于是乘着小明上厕所的时候，擦掉小明的Code，自己写了一段高大上的Code："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "except: division by zero\n",
      "finally：小明是傻子～\n",
      "----------\n",
      "小明啊小明你调坑里了～\n",
      "else：没有异常就奖励100块～\n",
      "finally：小明是傻子～\n"
     ]
    }
   ],
   "source": [
    "# 异常捕获全格式\n",
    "def test(input_str):\n",
    "    try:\n",
    "        eval(input_str)\n",
    "    except ZeroDivisionError as ex:\n",
    "        print(\"except:\", ex)\n",
    "    else:\n",
    "        print(\"else：没有异常就奖励100块～\")\n",
    "    finally:\n",
    "        print(\"finally：小明是傻子～\")\n",
    "\n",
    "\n",
    "def main():\n",
    "    test(\"1/0\")\n",
    "    print(\"-\" * 10)\n",
    "    test(\"print('小明啊小明你调坑里了～')\")\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这时候小明和老师一起进来了，同学们隐约间都听到小明的自夸声：“老师，我可好了，提前预习并且还写了个demo在黑板上呢～”\n",
    "\n",
    "老师一进门看着黑板就笑了，同学们也笑成一片。小明心想，咦～难道我写错了？定眼一看黑板，气呼呼的回座位了\n",
    "\n",
    "`else`可以不写，不过我们 **基本上还是会写的，毕竟可以知道是真的没有错误，而不是屏蔽了错误**\n",
    "\n",
    "### 1.3 多个异常处理\n",
    "\n",
    "老师很欣慰，觉得这个班真有意思，大家学习空前热情，为了照顾小明，老师反问道：“有谁知道 **多个异常怎么处理**？”\n",
    "\n",
    "小明飞快的举手并把黑板上内容擦完，写下了如下代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name 'xiaopan' is not defined\n"
     ]
    }
   ],
   "source": [
    "# 多个异常捕获\n",
    "def main():\n",
    "    try:\n",
    "        print(xiaopan)  # NameError: name 'xiaopan' is not defined\n",
    "        1 / 0  # ZeroDivisionError: division by zero\n",
    "    except NameError as ex:\n",
    "        print(ex)\n",
    "    except ZeroDivisionError as ex:\n",
    "        print(ex)\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "老师问了小明一声，有几个输出？\n",
    "\n",
    "小明骄傲的说道：“两个，我写了两个异常处理，当然都执行了”\n",
    "\n",
    "同学们又笑了，小潘调侃的说了句：“一看就知道去年C#没好好学，这不都一样嘛，**遇到异常下面代码还执行吗**？用脑子好好想想”\n",
    "\n",
    "当我们认为某些代码可能会出错时，就可以用`try`来运行这段代码，如果执行出错，则后续代码不会继续执行，而是直接跳转至`except`语句块，执行完`except`后，如果有`finally`语句块，则执行finally语句块\n",
    "\n",
    "小明又尴尬了。。。\n",
    "\n",
    "### 1.4 多异常简写\n",
    "\n",
    "老师再次帮小明圆了个场：“已经很不简单了，就是最后小得意的时候口误了，那小明同学你知道Python里面多异常有个便捷写法吗？”\n",
    "\n",
    "小明赶紧拿起粉笔刷刷刷的写完，然后说道：“**of course**”"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name 'xiaopan' is not defined\n"
     ]
    }
   ],
   "source": [
    "# 多个异常捕获的简写(注意哦，是元组哦)\n",
    "def main():\n",
    "    try:\n",
    "        print(xiaopan)  # NameError: name 'xiaopan' is not defined\n",
    "        1 / 0  # ZeroDivisionError: division by zero\n",
    "    except (NameError, ZeroDivisionError) as ex:\n",
    "        print(ex)\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "老师赶紧夸了夸小明，心想，哎呦喂终于把这难缠的家伙弄回座位了。\n",
    "\n",
    "小明走前还不忘说一句：“简写的时候注意格式哦，是 **元组** 不是逗号分隔”\n",
    "\n",
    "老师这堂课很轻松，大家都预习了而且内容也比较简单。\n",
    "\n",
    "接着以提问的方式问道：“小潘同学，你知道异常的基类是什么吗？如果要捕获所有异常该怎么做呢？”\n",
    "\n",
    "小潘站起来说道：“是`BaseException`”\n",
    "\n",
    "老师扩充道：“所有的错误类型都继承自`BaseException`，所以在使用`except`时需要注意的是，它不但捕获该类型的错误，还把其子类也一起捕获了”\n",
    "\n",
    "所以一般在捕获异常的时候 **把子类异常放在前面，父类放在后面**\n",
    "\n",
    "看如下代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "base: division by zero\n"
     ]
    }
   ],
   "source": [
    "def main():\n",
    "    try:\n",
    "        1 / 0  # ZeroDivisionError: division by zero\n",
    "    except BaseException as ex:\n",
    "        print(\"base:\", ex)\n",
    "    except ZeroDivisionError as ex:\n",
    "        print(ex)\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果把父类放第一个，那么`ZeroDivisionError`永远也不会被执行了，其实你如果装了 **代码规范提示**插件会提示你的\n",
    "\n",
    "可以参考我之前写的 <a href=\"https://www.cnblogs.com/dotnetcrazy/p/9095793.html\" target=\"_blank\">vscode设置python3调试环境的扩充部分</a>\n",
    "\n",
    "来个通用异常捕获的简写（官方不推荐使用简写）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "屏蔽错误\n"
     ]
    }
   ],
   "source": [
    "# 直接except就行了\n",
    "def main():\n",
    "    try:\n",
    "        1 / 0\n",
    "        dnt += 1\n",
    "    except:\n",
    "        print(\"屏蔽错误\")\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "老师继续讲到，我们来看一个场景，现在很多在线编辑器，你在他们那些编辑框里写下了代码也是有异常抛出的，这是怎么处理的呢？\n",
    "\n",
    "微软有开源代码编辑器比较受欢迎（VSCode的一部分）：<a href=\"https://microsoft.github.io/monaco-editor\" target=\"_blank\">monaco-editor</a>\n",
    "\n",
    "提示一下，如果真的要做在线编辑器，记得考虑一下`fork炸弹`，这个其实也是很老的东西了，程序员基本上都应该接触过了\n",
    "\n",
    "### 1.5 抛出异常\n",
    "\n",
    "我们继续，像C#是用`thorw`抛出异常，那Python怎么 `捕获异常后再抛出` 呢？怎么`自定义异常` 呢？\n",
    "\n",
    "继续往下看："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "division by zero\n"
     ]
    },
    {
     "ename": "ZeroDivisionError",
     "evalue": "division by zero",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mZeroDivisionError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-7-15f01346e2d8>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m__name__\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'__main__'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m     \u001b[0mmain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-7-15f01346e2d8>\u001b[0m in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mmain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m     \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m         \u001b[0;36m1\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0;36m0\u001b[0m  \u001b[0;31m# ZeroDivisionError: division by zero\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      5\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0mZeroDivisionError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mex\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m         \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mex\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# 写个日志，回头出问题可以深究\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero"
     ]
    }
   ],
   "source": [
    "# 捕获异常后再丢出，eg：在线运行的用户Code\n",
    "def main():\n",
    "    try:\n",
    "        1 / 0  # ZeroDivisionError: division by zero\n",
    "    except ZeroDivisionError as ex:\n",
    "        print(ex)  # 写个日志，回头出问题可以深究\n",
    "        raise\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "ename": "DntException",
     "evalue": "num must>0",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mDntException\u001b[0m                              Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-8-7c9dec6ec225>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     18\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m__name__\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'__main__'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m     \u001b[0mmain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-8-7c9dec6ec225>\u001b[0m in \u001b[0;36mmain\u001b[0;34m()\u001b[0m\n\u001b[1;32m     12\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     13\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mmain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m     \u001b[0mget_age\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     15\u001b[0m     \u001b[0mget_age\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m22\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# 程序崩了，这句话不会被执行了\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m<ipython-input-8-7c9dec6ec225>\u001b[0m in \u001b[0;36mget_age\u001b[0;34m(num)\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mget_age\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mnum\u001b[0m \u001b[0;34m<=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mDntException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"num must>0\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      9\u001b[0m     \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m         \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mDntException\u001b[0m: num must>0"
     ]
    }
   ],
   "source": [
    "# 抛出自定义异常\n",
    "class DntException(BaseException):\n",
    "    pass\n",
    "\n",
    "\n",
    "def get_age(num):\n",
    "    if num <= 0:\n",
    "        raise DntException(\"num must>0\")\n",
    "    else:\n",
    "        print(num)\n",
    "\n",
    "\n",
    "def main():\n",
    "    get_age(-1)\n",
    "    get_age(22)  # 程序崩了，这句话不会被执行了\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "异常这一块基本上讲完了（`logging`模块后面会说）有什么补充的可以说的^_^"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.6 C#异常\n",
    "\n",
    "小明又进行了C#的代码转换，怎么看都觉得还是C#简单啊，根本不用说啥，代码一贴就秒懂了。。。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Input string was not in a correct format.\n"
     ]
    }
   ],
   "source": [
    "%%script csharp\n",
    "try\n",
    "{\n",
    "    Convert.ToInt32(\"mmd\");\n",
    "}\n",
    "catch (Exception ex)\n",
    "{\n",
    "    // Input string was not in a correct format\n",
    "    Console.WriteLine(ex.Message);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "出错了啊\n"
     ]
    }
   ],
   "source": [
    "%%script csharp\n",
    "//抛出自定义异常\n",
    "try\n",
    "{\n",
    "    throw new Exception(\"出错了啊\");\n",
    "}\n",
    "catch (Exception ex)\n",
    "{\n",
    "    Console.WriteLine(ex.Message);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你可以自定义异常类，继承Exception即可，对了C#里面也是有finally的\n",
    "```csharp\n",
    "try\n",
    "{\n",
    "    throw new Exception(\"出错了啊\");\n",
    "    //Convert.ToInt32(\"mmd\");\n",
    "}\n",
    "catch (Exception ex)\n",
    "{\n",
    "    // Input string was not in a correct format\n",
    "    Console.WriteLine(ex.Message);\n",
    "}\n",
    "finally\n",
    "{\n",
    "    Console.WriteLine(\"finally\");\n",
    "}\n",
    "```\n",
    "\n",
    "现在一些需要finally的地方基本上都被using(){}接管了，所以特定场景会使用\n",
    "\n",
    "先这样了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
